home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / CLLZW.CPP < prev    next >
C/C++ Source or Header  |  1995-09-11  |  23KB  |  820 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    class.cpp
  5. //   Title:    C++ Class Libraries
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be 
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$    
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //    This module contains code for the class CL_LZW.
  24. //    This is a very simplified LZW-type compressor/expander. It handles binary 
  25. //    files but it always outputs 1.5 byte codes. This means that as a worst
  26. //    case, a buffer can end up being 1.5 times it's original size.
  27. //
  28. //    Some of the routines in this module have been 'unrolled' to speed 
  29. //    things up. Be very careful when changing code since this module was 
  30. //    profiled and hand optimized (and it is still slow!).
  31. //
  32. //    This class is very large, it should be allocated dynamically.
  33. //
  34. //    The code in this module may be written in C++ or C.
  35. //
  36. //    This module is portable to:
  37. //        DOS 3.X+
  38. //        MS Windows 3.X+
  39. //        OS/2 2.X+
  40. //        OS/2 2.0 PM
  41. //
  42. //    The following compilers are supported:
  43. //        MSC 6.0A
  44. //        MSC/C++ 7.0
  45. //        Borland C++ 3.1 for DOS
  46. //        Borland C++ 1.0 for OS/2 2.X
  47. //
  48. //----------------------------------------------------------------------------
  49. #include <class.hpp>
  50.  
  51.  
  52. //----------------------------------------------------------------------------
  53. //    Constants
  54. //----------------------------------------------------------------------------
  55. #define LZW_BUF1    (8192)
  56. #define LZW_BUF2    (LZW_BUF1+LZW_BUF1/2)
  57. #if OS_UNIX
  58. #    define LF    "\n"
  59. #else
  60. #    define LF    "\r\n"
  61. #endif
  62.  
  63. #define CTRLZ    "\x1A"
  64.  
  65. #define LZWVER    (0x0100)
  66. #define LZWID    (0x12348765L)
  67.  
  68. static CHAR szHeaderFormat[] =            // File header format text
  69.     "Compressed File v%d.%02d" LF
  70.     "%s" LF
  71.     "Created %2d:%02d:%02d %2d/%02d/%4d" LF
  72.     CTRLZ;
  73.  
  74. typedef struct _LZWHDR                        // Configuration file header
  75. {
  76.     CHAR szText[256];                            // Header description
  77.     LONG lId;                                    // Identifier word
  78.     USHORT usVer;                                // File version
  79.     CRC crc;                                        // CRC of file
  80.     TIMET timet;                                // Time file was created
  81.     USHORT usAttrib;                            // File attributes
  82.     BYTE bUnused[256 - 4 - 2 - 4 - 4 - 2];
  83. } LZWHDR;                                        
  84. BASETYPE(LZWHDR);
  85.  
  86. //----------------------------------------------------------------------------
  87. //   Description:    Default constructor
  88. //    Parameters:
  89. //       Returns:    
  90. //----------------------------------------------------------------------------
  91. FN_M CL_LZW::CL_LZW()
  92. {
  93.     CL_LZW::Initialize(CL_INIT_CLASS);
  94. }
  95.  
  96.  
  97. //----------------------------------------------------------------------------
  98. //   Description:    Copy constructor
  99. //    Parameters:    rccl_lzw        Reference to object to copy.
  100. //       Returns:    
  101. //----------------------------------------------------------------------------
  102. FN_M CL_LZW::CL_LZW(RCCL_LZW rccl_lzw)
  103. {
  104.     CL_LZW::Initialize(CL_INIT_CLASS);
  105.     *this = rccl_lzw;
  106. }
  107.  
  108.  
  109. //----------------------------------------------------------------------------
  110. //   Description:    Destructor
  111. //    Parameters:
  112. //       Returns:    
  113. //----------------------------------------------------------------------------
  114. FN_M CL_LZW::~CL_LZW()
  115. {
  116.     CL_LZW::Destroy(FALSE);
  117. }
  118.  
  119.  
  120. //----------------------------------------------------------------------------
  121. //   Description:    Add a symbol to the table. Ignore if table is full
  122. //    Parameters:    sSym1        Symbols
  123. //                        sSym2        Symbols
  124. //       Returns:
  125. //----------------------------------------------------------------------------
  126. VOID FN_M CL_LZW::Add(SHORT sSym1, SHORT sSym2)
  127. {
  128.     if (cSym < LZW_SYMBOLS)
  129.         {
  130.         asym[cSym].cLen = asym[sSym1].cLen + asym[sSym2].cLen;
  131.         asym[cSym].sSym[0] = sSym1;
  132.         asym[cSym].sSym[1] = sSym2;
  133.         sSym1 = (SHORT)asym[sSym1].sFirst;
  134.         asym[cSym].sFirst = (BYTE)sSym1;
  135.         asym[cSym].sNext = asym[sSym1].sNext;
  136.         asym[sSym1].sNext = (SHORT)cSym;
  137.         cSym++;
  138.         if (cSym == 2048)
  139.             cBits = 12;
  140.         else if (cSym == 1024)
  141.             cBits = 11;
  142.         else if (cSym == 512)
  143.             cBits = 10;
  144.         }
  145.     return ;
  146. }
  147.  
  148.  
  149. //----------------------------------------------------------------------------
  150. //   Description:    Encode a buffer.
  151. //    Parameters:    _pbIn        Pointer to input buffer
  152. //                        _cbIn        Size of input buffer
  153. //                   _pbOut    Pointer to output buffer
  154. //                        _cbOut    Size of output buffer
  155. //       Returns:    Size of encoded buffer or 0
  156. //----------------------------------------------------------------------------
  157. SIZET FN_M CL_LZW::Decode(PBYTE _pbIn, SIZET _cbIn, PBYTE _pbOut, SIZET _cbOut)
  158. {
  159.     Assert(_pbIn && _cbIn);
  160.     Assert(_pbOut && _cbOut);
  161.     CL_LZW::Initialize();
  162.     pbIn  = _pbIn;
  163.     cbIn  = _cbIn;
  164.     pbOut = _pbOut;
  165.     cbOut = _cbOut;
  166.     SHORT sPrev = -1;
  167.     SHORT sSym;
  168.  
  169.     while ((sSym = Read()) != -1)
  170.         {
  171.        if (sSym < 256)                        // An ascii symbol
  172.            {
  173.            if (!cbOut)
  174.                return 0;
  175.    
  176.            *pbOut = (BYTE)sSym;
  177.            pbOut++;
  178.            cbOut--;
  179.            cbData++;
  180.            }
  181.         else if (!Expand(sSym))                // Expand the hard way
  182.             return 0;
  183.         if (sPrev >= 0)                        // Add new symbol to table
  184.             Add(sPrev, sSym);
  185.         sPrev = sSym;                            // Save current symbol
  186.         }
  187.     return cbData;
  188. }
  189.  
  190.  
  191. //----------------------------------------------------------------------------
  192. //   Description:    Decode a file.
  193. //    Parameters:    pcszOut    Output file name.
  194. //                        pcszIn    Input file name.
  195. //                                    If null, a default file name is created.
  196. //                                    Default is NULL.
  197. //                        pfnlzw    Callback function to monitor progress
  198. //       Returns:    Size of encoded buffer or 0
  199. //----------------------------------------------------------------------------
  200. BOOL FN_M CL_LZW::DecodeFile(PCSZ pcszOut, PCSZ pcszIn, PFNLZW pfnlzw)
  201. {
  202.     CHAR szIn[MAX_PATH];
  203.     FLAG16 fs1 = FL_CREATE|FL_TRUNCATE|FL_READWRITE|FL_DENYREADWRITE|FL_BINARY;
  204.     FLAG16 fs2 = FL_OPEN|FL_READWRITE|FL_DENYREADWRITE|FL_BINARY;
  205.     FPOS fsize = 0;
  206.     HF hf1 = -1, hf2 = -1;
  207.     PBYTE pbBuf1 = NULL, pbBuf2 = NULL;
  208.     BOOL fResult = FALSE;
  209.     LONG lTotal = 0;
  210.     LZWHDR lzwhdr;
  211.     CRC crc = 0;
  212.     BS_FINFO finfo;
  213.  
  214.     Assert(pcszOut);
  215.     if (pcszIn == NULL)
  216.         {
  217.         strcpy(szIn, pcszOut);
  218.         pcszIn = szIn;
  219.         FnameAppendExt(szIn, "$$$", TRUE);
  220.         }
  221.     pbBuf1 = (PBYTE)MemAlloc(LZW_BUF1);
  222.     pbBuf2 = (PBYTE)MemAlloc(LZW_BUF1);
  223.     if (pbBuf1 == NULL || pbBuf2 == NULL)
  224.         {
  225.         ErrorNoMem();
  226.         goto ERROR_EXIT;
  227.         }
  228.     if (!FileOpen(&hf1, pcszOut, fs1, NULL))
  229.         goto ERROR_EXIT;
  230.     if (!FileOpen(&hf2, pcszIn, fs2, NULL))
  231.         goto ERROR_EXIT;
  232.     fsize = FileGetSize(hf2);
  233.     if (fsize <= sizeof(LZWHDR))
  234.         goto ERROR_EXIT;
  235.     if (!FileRead(hf2, &lzwhdr, sizeof(lzwhdr), 0))
  236.         goto ERROR_EXIT;
  237.     fsize -= (FPOS)sizeof(LZWHDR);
  238.     if (lzwhdr.lId != LZWID || lzwhdr.usVer != LZWVER)
  239.         {
  240.         Error("Invalid compressed file format.");
  241.         goto ERROR_EXIT;
  242.         }
  243.     FileSetPos(hf1, 0, FL_BEGIN);
  244.     FileSetPos(hf2, sizeof(LZWHDR), FL_BEGIN);
  245.     lTotal = fsize;
  246.     while (fsize)
  247.         {
  248.         if (pfnlzw)
  249.             pfnlzw(lTotal - (long)fsize, lTotal);
  250.         if (fsize < sizeof(SIZET))
  251.             goto ERROR_EXIT;
  252.         SIZET cRead;
  253.         if (!FileRead(hf2, (PBYTE)&cRead, sizeof(cRead), -1))
  254.             goto ERROR_EXIT;
  255.         fsize -= (FPOS)sizeof(cRead);
  256.         SIZET cActual = cRead & 0x7FFF;
  257.         if (fsize < (FPOS)cActual || cActual > LZW_BUF1)
  258.             goto ERROR_EXIT;
  259.         if (!FileRead(hf2, pbBuf2, cActual, -1))
  260.             goto ERROR_EXIT;
  261.         fsize -= (FPOS)cActual;
  262.         if (cRead & 0x8000)
  263.             {
  264.             crc = CrcCalcAppend(pbBuf2, cActual, crc);
  265.             if (!FileWrite(hf1, pbBuf2, cActual, -1))
  266.                 goto ERROR_EXIT;
  267.             }
  268.         else
  269.             {
  270.             SIZET cDecode;
  271.             cDecode = Decode(pbBuf2, cActual, pbBuf1, LZW_BUF1);
  272.             if (!cDecode || cDecode <  cRead || cDecode > LZW_BUF1)
  273.                 goto ERROR_EXIT;
  274.             crc = CrcCalcAppend(pbBuf1, cDecode, crc);
  275.             if (!FileWrite(hf1, pbBuf1, cDecode, -1))
  276.                 goto ERROR_EXIT;
  277.             }
  278.         }
  279.     if (crc != lzwhdr.crc)
  280.         {
  281.         Error("Error in compressed file.\nInvalid CRC.");
  282.         goto ERROR_EXIT;
  283.         }
  284.     FileClose(hf1);
  285.     hf1 = -1;
  286.     memset(&finfo, 0, sizeof(finfo));
  287.     finfo.timet = lzwhdr.timet;
  288.     finfo.usAttrib = lzwhdr.usAttrib;
  289.     if (!FinfoSet(pcszOut, &finfo))
  290.         goto ERROR_EXIT;
  291.     fResult = TRUE;
  292.  
  293. ERROR_EXIT:
  294.     if (pfnlzw)
  295.         pfnlzw(lTotal - (long)fsize, lTotal);
  296.     if (hf1 >= 0)
  297.         FileClose(hf1);
  298.     if (hf2 >= 0)
  299.         FileClose(hf2);
  300.     if (pbBuf1)
  301.         MemFree(pbBuf1);
  302.     if (pbBuf2)
  303.         MemFree(pbBuf2);
  304.     return fResult;
  305. }
  306.  
  307.  
  308. //----------------------------------------------------------------------------
  309. //   Description:    Destroy object. Free any resources used by object.
  310. //                          Normally called by destructor.
  311. //                        Should allow multiple calls from various classes.
  312. //                        A class should almost always re-init its variables when
  313. //                        it is destroyed to prevent accidents.
  314. //    Parameters:    fDestroyAll        Destroy parents also?
  315. //                                            Default is TRUE.
  316. //       Returns:    TRUE if successful.
  317. //----------------------------------------------------------------------------
  318. BOOL FN_M CL_LZW::Destroy(BOOL fDestroyAll)
  319. {
  320.     Initialize(CL_INIT_CLASS_VARS);
  321.     if (fDestroyAll)                            // Destroy parent.
  322.         CL_LZW_PARENT::Destroy(fDestroyAll);
  323.     return TRUE;
  324. }
  325.  
  326.  
  327. //----------------------------------------------------------------------------
  328. //   Description:    Encode a buffer.
  329. //    Parameters:    _pbIn        Pointer to input buffer
  330. //                        _cbIn        Size of input buffer
  331. //                   _pbOut    Pointer to output buffer
  332. //                        _cbOut    Size of output buffer
  333. //       Returns:    Size of encoded buffer or 0
  334. //----------------------------------------------------------------------------
  335. SIZET FN_M CL_LZW::Encode(PBYTE _pbIn, SIZET _cbIn, PBYTE _pbOut, SIZET _cbOut)
  336. {
  337.     Assert(_pbIn && _cbIn);
  338.     Assert(_pbOut && _cbOut);
  339.     Assert(_cbOut >= ((_cbIn * 3) + 1) / 2);
  340.     Initialize();
  341.     pbIn  = _pbIn;
  342.     cbIn  = _cbIn;
  343.     pbOut = _pbOut;
  344.     cbOut = _cbOut;
  345.     SHORT sPrev = -1;
  346.     SHORT sSym;
  347.     while (cbIn)
  348.         {
  349.         sSym = (SHORT)*pbIn;                    // Assume ASCII symbol
  350.         SHORT sNext = asym[sSym].sNext;
  351.         for (; sNext >= 0; sNext = asym[sNext].sNext)
  352.             if (asym[sNext].cLen <= cbIn
  353.             && asym[sNext].cLen > asym[sSym].cLen
  354.             && asym[sNext].sFirst == *pbIn
  355.             && IsMatch(pbIn, sNext))
  356.                 sSym = sNext;
  357.  
  358.         if (!Write(sSym))                        // Write symbol
  359.             return 0;
  360.         if (sPrev >= 0)                        // Add new symbol to table
  361.             Add(sPrev, sSym);
  362.         sPrev = sSym;                            // Save current symbol
  363.         cbIn -= asym[sSym].cLen;            // Move to next byte
  364.         pbIn += asym[sSym].cLen;
  365.         }
  366.     return cbData;
  367. }
  368.  
  369.  
  370. //----------------------------------------------------------------------------
  371. //   Description:    Encode a file.
  372. //    Parameters:    pcszIn    Input file name.
  373. //                        pcszOut    Output file name.
  374. //                                    If null, a default file name is created.
  375. //                                    Default is NULL.
  376. //                        pfnlzw    Callback function to monitor progress
  377. //       Returns:    Size of encoded buffer or 0
  378. //----------------------------------------------------------------------------
  379. BOOL FN_M CL_LZW::EncodeFile(PCSZ pcszIn, PCSZ pcszOut, PFNLZW pfnlzw)
  380. {
  381.     CHAR szOut[MAX_PATH];
  382.     FLAG16 fs1 = FL_OPEN|FL_READWRITE|FL_DENYREADWRITE|FL_BINARY;
  383.     FLAG16 fs2 = FL_CREATE|FL_TRUNCATE|FL_READWRITE|FL_DENYREADWRITE|FL_BINARY;
  384.     FPOS fsize = 0;
  385.     HF hf1 = -1, hf2 = -1;
  386.     PBYTE pbBuf1 = NULL, pbBuf2 = NULL;
  387.     BOOL fResult = FALSE;
  388.     LONG lTotal = 0;
  389.     LZWHDR lzwhdr;
  390.     time_t now = time(NULL);
  391.     struct tm *tm = localtime(&now);
  392.     BS_FINFO finfo;
  393.  
  394.     Assert(pcszIn);
  395.     if (!FnameIsFile(pcszIn))
  396.         return Error("Input file not found.");
  397.     Assert(sizeof(LZWHDR) == 512);
  398.     if (pcszOut == NULL)
  399.         {
  400.         strcpy(szOut, pcszIn);
  401.         pcszOut = szOut;
  402.         FnameAppendExt(szOut, "$$$", TRUE);
  403.         }
  404.     pbBuf1 = (PBYTE)MemAlloc(LZW_BUF1);
  405.     pbBuf2 = (PBYTE)MemAlloc(LZW_BUF2);
  406.     if (pbBuf1 == NULL || pbBuf2 == NULL)
  407.         {
  408.         ErrorNoMem();
  409.         goto ERROR_EXIT;
  410.         }
  411.     if (!FinfoGet(pcszIn, &finfo))
  412.         goto ERROR_EXIT;
  413.  
  414.     if (!FileOpen(&hf1, pcszIn, fs1, NULL))
  415.         goto ERROR_EXIT;
  416.     fsize = FileGetSize(hf1);
  417.     if (fsize <= 0)
  418.         goto ERROR_EXIT;
  419.     if (!FileOpen(&hf2, pcszOut, fs2, NULL))
  420.         goto ERROR_EXIT;
  421.                                                     // Write header
  422.     memset(&lzwhdr, 0, sizeof(lzwhdr));
  423.     sprintf(lzwhdr.szText,                    
  424.         szHeaderFormat,
  425.         (int)((LZWVER >> 8) & 0x00FF),
  426.         (int)(LZWVER & 0x00FF),
  427.         CfgGet(CFG_COPYRIGHT),
  428.         tm->tm_hour, tm->tm_min, tm->tm_sec,
  429.         tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
  430.     lzwhdr.lId = LZWID;
  431.     lzwhdr.usVer = LZWVER;
  432.     lzwhdr.crc = 0;
  433.     lzwhdr.timet = finfo.timet;
  434.     lzwhdr.usAttrib = finfo.usAttrib;
  435.     if (!FileWrite(hf2, &lzwhdr, sizeof(lzwhdr), 0))
  436.         goto ERROR_EXIT;
  437.     FileSetPos(hf1, 0, FL_BEGIN);
  438.     FileSetPos(hf2, sizeof(LZWHDR), FL_BEGIN);
  439.     lTotal = fsize;
  440.     while (fsize)
  441.         {
  442.         if (pfnlzw)
  443.             pfnlzw(lTotal - (long)fsize, lTotal);
  444.         SIZET cRead = (SIZET)MIN((FPOS)LZW_BUF1, fsize);
  445.         if (!FileRead(hf1, pbBuf1, cRead, -1))
  446.             goto ERROR_EXIT;
  447.  
  448.         lzwhdr.crc = CrcCalcAppend(pbBuf1, cRead, lzwhdr.crc);
  449.  
  450.         SIZET cEncode;
  451.         cEncode = Encode(pbBuf1, cRead, pbBuf2, LZW_BUF2);
  452.         if (!cEncode)
  453.             goto ERROR_EXIT;
  454.  
  455.         if (cEncode >= cRead)
  456.             cEncode = 0x8000|cRead;
  457.  
  458.         if (!FileWrite(hf2, (PBYTE)&cEncode, sizeof(cEncode), -1))
  459.             goto ERROR_EXIT;
  460.  
  461.         if (cEncode >= cRead)
  462.             {
  463.             if (!FileWrite(hf2, pbBuf1, cRead, -1))
  464.                 goto ERROR_EXIT;
  465.             }
  466.         else
  467.             {
  468.             if (!FileWrite(hf2, pbBuf2, cEncode, -1))
  469.                 goto ERROR_EXIT;
  470.             }
  471.         fsize -= (FPOS)cRead;
  472.         }                                            // Write updated CRC code
  473.     if (!FileWrite(hf2, &lzwhdr, sizeof(lzwhdr), 0))
  474.         goto ERROR_EXIT;
  475.     fResult = TRUE;
  476. ERROR_EXIT:
  477.     if (pfnlzw)
  478.         pfnlzw(lTotal - (long)fsize, lTotal);
  479.     if (hf1 >= 0)
  480.         FileClose(hf1);
  481.     if (hf2 >= 0)
  482.         FileClose(hf2);
  483.     if (pbBuf1)
  484.         MemFree(pbBuf1);
  485.     if (pbBuf2)
  486.         MemFree(pbBuf2);
  487.     return fResult;
  488. }
  489.  
  490.  
  491. //----------------------------------------------------------------------------
  492. //   Description:    Expand a symbol into a string
  493. //                          This function is recursive!!
  494. //    Parameters:    sSym        Symbol
  495. //       Returns:    TRUE if successful.
  496. //----------------------------------------------------------------------------
  497. BOOL FN_M CL_LZW::Expand(SHORT sSym)
  498. {
  499.     SHORT sSym1 = asym[sSym].sSym[0];   // Expand sub-strings (recurse)
  500.     SHORT sSym2 = asym[sSym].sSym[1];
  501.     if (sSym1 < 256)                            // An ascii symbol
  502.         {
  503.         if (!cbOut)
  504.             return FALSE;
  505.  
  506.         *pbOut = (BYTE)sSym1;
  507.         pbOut++;
  508.         cbOut--;
  509.         cbData++;
  510.         }
  511.     else if (!Expand(sSym1))
  512.         return FALSE;
  513.     if (sSym2 < 256)                            // An ascii symbol
  514.         {
  515.         if (!cbOut)
  516.             return FALSE;
  517.  
  518.         *pbOut = (BYTE)sSym2;
  519.         pbOut++;
  520.         cbOut--;
  521.         cbData++;
  522.         }
  523.     else if (!Expand(sSym2))
  524.         return FALSE;
  525.     return TRUE;
  526. }
  527.  
  528.  
  529. //----------------------------------------------------------------------------
  530. //   Description:    Initialize object. 
  531. //                          Normally called by constructor.
  532. //                        Should allow multiple calls from various classes.
  533. //    Parameters:    sInit        Initialization code. May be one of the following:
  534. //                                        CL_INIT_CLASS            Reset class variables and
  535. //                                                                    and dynamic allocations for
  536. //                                                                    this class only.
  537. //                                        CL_INIT_CLASS_VARS    Reset class variables for
  538. //                                                                    this class only.
  539. //                                        CL_INIT_VARS            Reset class variables for
  540. //                                                                    this class only.
  541. //                                        CL_INIT_ALL                Initialize class and all 
  542. //                                                                    parent class, including
  543. //                                                                    dynamic memory allocation.
  544. //                                    Default is CL_INIT_ALL
  545. //       Returns:    TRUE if successful.
  546. //----------------------------------------------------------------------------
  547. BOOL FN_M CL_LZW::Initialize(SHORT sInit)
  548. {
  549.     if (sInit == CL_INIT_VARS || sInit == CL_INIT_ALL)
  550.         CL_LZW_PARENT::Initialize(sInit);
  551.  
  552.     memset(asym, 0, sizeof(asym));
  553.     for (cSym = 0; cSym < 256; ++cSym)    // Add ascii symbols
  554.         {
  555.         asym[cSym].cLen = 1;
  556.         asym[cSym].sSym[0] = (SHORT)cSym;
  557.         asym[cSym].sFirst = (BYTE)cSym;
  558.         asym[cSym].sNext = -1;
  559.         }
  560.     cbData = 0;
  561.     cBitsLeft = 8;
  562.     cBits = 9;
  563.     return TRUE;
  564. }
  565.  
  566.  
  567. //----------------------------------------------------------------------------
  568. //   Description:    Check if a string matches the specified symbol
  569. //                          This function is recursive!!
  570. //    Parameters:    pb            String
  571. //                        sSym        Symbol
  572. //       Returns:    TRUE if successful.
  573. //----------------------------------------------------------------------------
  574. BOOL FN_M CL_LZW::IsMatch(PBYTE pb, SHORT sSym)
  575. {
  576.     SHORT sSym1 = asym[sSym].sSym[0];    // Match sub-strings (recurse)
  577.     SHORT sSym2 = asym[sSym].sSym[1];
  578.     if (sSym1 < 256)                            // This routine has been unrolled
  579.         {                                            //  for speed
  580.         if (sSym2 < 256)
  581.             {
  582.             return pb[0] == (BYTE)sSym1 && pb[1] == (BYTE)sSym2;
  583.             }
  584.         else
  585.             {
  586.             return pb[0] == (BYTE)sSym1
  587.                 && pb[1] == (BYTE)asym[sSym2].sFirst
  588.                 && IsMatch(pb + 1, sSym2);
  589.             }
  590.         }
  591.     else
  592.         {
  593.         if (pb[0] != (BYTE)asym[sSym1].sFirst || !IsMatch(pb, sSym1))
  594.             return FALSE;
  595.  
  596.         PBYTE pb2 = pb + asym[sSym1].cLen;
  597.         if (sSym2 < 256)
  598.             {
  599.             return pb2[0] == (BYTE)sSym2;
  600.             }
  601.         else
  602.             {
  603.             return pb2[0] == (BYTE)asym[sSym2].sFirst
  604.                 && IsMatch(pb2, sSym2);
  605.             }
  606.         }
  607. }
  608.  
  609.  
  610. //----------------------------------------------------------------------------
  611. //   Description:    Assignment operator
  612. //                          NOTE: Don't copy object into self
  613. //    Parameters:    rccl_lzw        Reference to right value.
  614. //       Returns:    Reference to new object.
  615. //----------------------------------------------------------------------------
  616. RCCL_LZW FN_M CL_LZW::operator=(RCCL_LZW rccl_lzw)
  617. {
  618.     if (this != &rccl_lzw)
  619.         {
  620.         Invalid("CL_LZW::operator=");
  621.         }
  622.     return (RCCL_LZW)*this;
  623. }
  624.  
  625.  
  626. //----------------------------------------------------------------------------
  627. //   Description:    Read a symbol
  628. //    Parameters:    
  629. //       Returns:    Symbol or -1 for end of buffer
  630. //----------------------------------------------------------------------------
  631. SHORT FN_M CL_LZW::Read()
  632. {
  633.     SHORT sSym;
  634.     SIZET cBitsNeeded = cBits;
  635.  
  636.     if (cBitsLeft == 8)                        // Initialize byte for output
  637.         {
  638.         if (!cbIn)
  639.             return -1;
  640.         cbIn--;
  641.         }
  642.     sSym = *pbIn++;
  643.     cBitsNeeded -= cBitsLeft;
  644.     if (cBitsNeeded > 8)
  645.         {
  646.         if (!cbIn)
  647.             return -1;
  648.         cbIn--;
  649.         sSym <<= 8;
  650.         sSym |= *pbIn++;
  651.         cBitsNeeded -= 8;
  652.         }
  653.     if (!cbIn)
  654.         return -1;
  655.     cbIn--;
  656.     sSym <<= cBitsNeeded;
  657.     if (cBitsNeeded < 8)
  658.         {
  659.         cBitsLeft = 8 - cBitsNeeded;
  660.         sSym |= (SHORT)(*pbIn >> cBitsLeft);
  661.         }
  662.     else                                            // Exactly 8 bits left
  663.         {
  664.         sSym |= *pbIn++;
  665.         cBitsLeft = 8;
  666.         }
  667.     return (SHORT)(sSym & (0xFFFF >> (16 - cBits)));
  668. }
  669.  
  670.  
  671. //----------------------------------------------------------------------------
  672. //   Description:    Retrieve object from persistent storage
  673. //    Parameters:    pcsz        Name of object.
  674. //                        pcszSub    Sub-name of object.
  675. //                                    The first character of the name should be '~'.
  676. //                                    If NULL, no sub name is available.
  677. //                                    Default is NULL
  678. //       Returns:    TRUE if successful.
  679. //----------------------------------------------------------------------------
  680. BOOL FN_M CL_LZW::Retrieve(PCSZ pcsz, PCSZ pcszSub)
  681. {
  682.     NOTUSED(pcsz);
  683.     NOTUSED(pcszSub);
  684.     Invalid("CL_LZW::Retrieve");
  685.     return FALSE;
  686. }
  687.  
  688.  
  689. //----------------------------------------------------------------------------
  690. //   Description:    Store object to persistent storage
  691. //    Parameters:    pcsz        Name of object.
  692. //                        pcszSub    Sub-name of object.
  693. //                                    The first character of the name should be '~'.
  694. //                                    If NULL, no sub name is available.
  695. //                                    Default is NULL
  696. //       Returns:    TRUE if successful.
  697. //----------------------------------------------------------------------------
  698. BOOL FN_M CL_LZW::Store(PCSZ pcsz, PCSZ pcszSub)
  699. {
  700.     NOTUSED(pcsz);
  701.     NOTUSED(pcszSub);
  702.     Invalid("CL_LZW::Store");
  703.     return FALSE;
  704. }
  705.  
  706.  
  707. //----------------------------------------------------------------------------
  708. //   Description:    Write a symbol
  709. //    Parameters:    sSym        Symbol
  710. //       Returns:    TRUE if successful.
  711. //----------------------------------------------------------------------------
  712. BOOL FN_M CL_LZW::Write(SHORT sSym)
  713. {
  714.     SIZET cBitsNeeded = cBits;
  715.  
  716.     if (cBitsLeft == 8)                        // Initialize byte for output
  717.         {
  718.         cbData++;
  719.         if (cbData > cbOut)                        
  720.             return FALSE;
  721.         *pbOut = 0;
  722.         }                                            // Out remainder of current byte
  723.     *pbOut |= (sSym >> (cBitsNeeded - cBitsLeft));
  724.     cBitsNeeded -= cBitsLeft;
  725.     pbOut++;                                        // Move to next byte
  726.     if (cBitsNeeded > 8)
  727.         {
  728.         cbData++;                                
  729.         if (cbData > cbOut)                        
  730.             return FALSE;
  731.         *pbOut = ((BYTE)sSym >> (cBitsNeeded - 8));
  732.         pbOut++;
  733.         cBitsNeeded -= 8;
  734.         }
  735.     cbData++;                                
  736.     if (cbData > cbOut)                        
  737.         return FALSE;
  738.     *pbOut = (BYTE)sSym;
  739.     if (cBitsNeeded < 8)
  740.         {
  741.         cBitsLeft = 8 - cBitsNeeded;
  742.         *pbOut <<= cBitsLeft;
  743.         }
  744.     else                                            // Exactly 8 bits left
  745.         {
  746.         pbOut++;
  747.         cBitsLeft = 8;
  748.         }
  749.     return TRUE;
  750. }
  751.  
  752.  
  753. //----------------------------------------------------------------------------
  754. //   Description:    Run standard test suite on object.
  755. //    Parameters:    sTest        Test to run.
  756. //                                    If 0, run default tests.
  757. //                                    Default is 0.
  758. //       Returns:    TRUE if successful.
  759. //----------------------------------------------------------------------------
  760. #if COMPILE_DEBUG
  761. BOOL FN_M CL_LZW::Test(SHORT sTest)
  762. {
  763. #if COMPILE_TEST
  764. static CL_LZW _FAR_ cl_lzw;
  765. static BYTE bDecode[4096];
  766. static BYTE bEncode[4096 + (4096/2)];
  767. static PCSZ apcsz[] =
  768.     {
  769.     "ABCABC",
  770.     "A",
  771.     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
  772.     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  773.     "ABABABABABABABABABABABAB",
  774.     NULL
  775.     };
  776.  
  777.     if (sTest == 0)
  778.        for (SIZET i = 0; apcsz[i]; ++i)
  779.            {
  780.            Output("[%s]\n", apcsz[i]);
  781.            Output("  Input: %d\n", strlen(apcsz[i]) + 1);
  782.            SIZET cbEncode = cl_lzw.Encode((PBYTE)apcsz[i], strlen(apcsz[i]) + 1,
  783.                bEncode, sizeof(bEncode));
  784.            if (!cbEncode)
  785.                return FALSE;
  786.            Output("  Output: %d\n", cbEncode);
  787.            SIZET cbDecode = cl_lzw.Decode(bEncode, cbEncode, bDecode,
  788.                sizeof(bDecode));
  789.            if (cbDecode != strlen(apcsz[i]) + 1
  790.            || strcmp((PSZ)bDecode, apcsz[i]) != 0)
  791.                return FALSE;
  792.            }
  793.     if (sTest == 1)
  794.         {
  795.         PCSZ pcszFile = "test.dat";
  796.         if (!FnameIsFile(pcszFile))
  797.             {
  798.             return _Error("Could not find file '%s'.", pcszFile);
  799.             }
  800.         Output("Encoding...this may take several minutes...\n");
  801.         if (!cl_lzw.EncodeFile(pcszFile))
  802.             return FALSE;
  803.         }
  804.     if (sTest == 2)
  805.         {
  806.         Output("Decoding...\n");
  807.         if (!cl_lzw.DecodeFile("test.out"))
  808.             return FALSE;
  809.         }
  810.     return TRUE;
  811. #else
  812.     NOTUSED(sTest);
  813.     return TRUE;
  814. #endif
  815. }
  816. #endif
  817. //----------------------------------------------------------------------------
  818. //------------------------------- End of File --------------------------------
  819. //----------------------------------------------------------------------------
  820.